-- 展示表内容
---@param data table 数据源
function table.print(data)
    if type(data) == "table" then
        for k, v in pairs(data) do
            print(k .. " -> " .. v)
        end
    end
end

-- 统计元素数量
---@param data table 数据源
function table.size(data)
    local res = 0

    if type(data) == "table" then
        for _, _ in pairs(data) do
            res = res + 1
        end
    end

    return res
end

-- 移除表内查到的第一个元素
---@param data table 数据源
function table.remove_v(data, value)
    if type(data) == "table" then
        for k, v in pairs(data) do
            if v == value then
                if type(k) == "number" then
                    table.remove(data, k)
                else
                    data[k] = nil
                end
            end
        end
    end
end

-- 表元素内容连接
---@param data table 数据源
---@param sep string 分割符, 默认空字符串
function table.concat_v(data, sep)
    if type(data) == "table" then
        sep = type(sep) == "string" and sep or ""
        local res

        for _, v in pairs(data) do
            if not res then
                res = tostring(v)
            else
                res = res .. sep .. tostring(v)
            end
        end

        return res
    end
end

-- 表元素键名连接(键名遍历是降序)
---@param data table 数据源
---@param sep string 分割符, 默认空字符串
function table.concat_k(data, sep)
    if type(data) == "table" and table.size(data) > 0 then
        sep = type(sep) == "string" and sep or ""
        local res = ""

        for k, _ in pairs(data) do
            res = res .. sep .. tostring(k)
        end

        return res
    end
end

-- 获取随机元素
---@param data table 数据源
---@param r_key boolean 该值为true时, 同时返回该元素的键名
function table.random(data, r_key)
    assert(type(data) == "table", "数据源不是一个表")

    local key, value
    local size = table.size(data)

    if size > 0 then
        local choice = math.random(size)

        for k, v in pairs(data) do
            if choice <= 0 then
                key, value = k, v
                break
            end
            choice = choice - 1
        end
    end

    if r_key == true then
        return key, value
    else
        return value
    end
end

-- 元素顺序反转
---@param data table 数据源
---@param on_data boolean 在数据源上进行操作
function table.reverse(data, on_data)
    assert(type(data) == "table", "数据源不是一个表")

    local size = table.size(data)
    local res = {}

    if on_data == true then
        res = data
        local i, j = 1, size

        while i < j do
            res[i], res[j] = res[j], res[i]
            i = i + 1
            j = j - 1
        end
    else
        for i = size, 1, -1 do
            table.insert(res[i])
        end
    end

    return res
end

-- 过滤元素
---@param data table 数据源
---@param fn function 过滤函数, 保留返回值为true的元素
---@param mate_data table 用于接收符合条件的元素, 默认会创建一个新的表用于接收
function table.filter(data, fn, mate_data)
    assert(type(data) == "table", "数据源不是一个表")

    local res = type(mate_data) == "table" and mate_data or {}

    if fn == nil then
        for _, value in pairs(data) do
            if value ~= nil then
                table.insert(res, value)
            end
        end
    elseif type(fn) == "function" then
        for _, value in pairs(data) do
            if fn(value) == true then
                table.insert(res, value)
            end
        end
    end

    return res
end

-- 元素批量处理
---@param data table 数据源
---@param fn function 处理函数
---@param params table 处理函数处理元素时额外需要传入的处理参数
---@param on_data boolean 在数据源上进行操作
function table.map(data, fn, params, on_data)
    assert(type(data) == "table", "数据源不是一个表")
    assert(type(fn) == "function", "处理函数类型不正确: " .. type(fn))

    local res = on_data == true and data or {}

    for k, v in pairs(data) do
        res[k] = fn(v, params)
    end

    return res
end

-- 表合并插入数据
---@param t table 待插入数据的表
---@param value any 待插入的数据
---@param allowable_nil boolean 插入数据可以为nil
---@param repeatable boolean 插入数据可以重复
local function merge_insert(t, value, allowable_nil, repeatable)
    allowable_nil = type(allowable_nil) == "boolean" and allowable_nil or true
    repeatable = type(repeatable) == "boolean" and repeatable or true

    if value == nil and not allowable_nil then
        return
    end

    if repeatable or not table.contains(t, value) then
        table.insert(t, value)
    end
end

-- 多表合并(用于合并列表)
---@param t1 table 表1, 合并表
---@param t2 table 表2, 被合并表, 表元素将合并至合并表
---@param t2_merges boolean 当该值为true时, 表2内的表元素作为被合并表, 表内元素拆分合并至合并表
---@param new_table boolean 当该值为true时, 将创建一个新的表作为合并表, 表1将作为被被合并表
---@param allowable_nil boolean 被合并数据可以为nil
---@param repeatable boolean 被合并数据可以重复
function table.merge(t1, t2, t2_merges, new_table, allowable_nil, repeatable)
    assert(type(t1) == "table", "基础合并表类型不正确")

    local res = t1
    if new_table == true then
        res = {}
        for _, v in pairs(t1) do
            merge_insert(res, v, allowable_nil, repeatable)
        end
    end

    for _, v1 in pairs(t2) do
        if type(v1) == "table" and t2_merges == true then
            for _, v2 in pairs(v1) do
                merge_insert(res, v2, allowable_nil, repeatable)
            end
        else
            merge_insert(res, v1, allowable_nil, repeatable)
        end
    end

    return res
end

-- 多表合并(用于合并对象)
---@param list table 待合并表列表
---@param new_table boolean 当该值为true时, 将创建一个新的表作为初始合并表, 否则以待合并表列表第一个表作为初始合并表
---@param key_repeatable boolean 当该值为true且元素键名相同时, 后续合并值会覆盖前面的值
function table.merge_maps(list, new_table, key_repeatable)
    assert(type(list) == "table", "合并表列表类型不正确")

    local res

    if new_table == true then
        res = {}
    end

    for _, t in pairs(list) do
        if res and type(t) == "table" then
            for k, v in pairs(t) do
                if key_repeatable or not table.containskey(res, k) then
                    res[k] = v
                end
            end
        elseif not res and type(t) == "table" then
            res = t
        end
    end

    return res
end

-- 默认冒泡比较
local function default_comp(v1, v2) return v1 < v2 end

-- 混合排序
---@param v1 any 列表元素1
---@param v2 any 列表元素2
---@param comp function 自定义冒泡排序函数(默认升序), 接收两个元素, 返回布尔值, true交换两个位置, false保持不变
---@param o_fn function 其它类型元素自定义排序函数(如对象类型), 返回布尔值, true交换两个位置, false保持不变
local function mixed_comp(v1, v2, comp, o_fn)
    local type_v1, type_v2 = type(v1), type(v2)
    comp = type(comp) == "function" and comp or default_comp

    if type_v1 == type_v2 then
        if type_v1 == "string" or type_v1 == "number" then
            return comp(v1, v2)
        end
        return type(o_fn) == "function" and o_fn(v1, v2) or false
    end

    if type_v1 == "number" then
        return false
    end

    if type_v2 == "number" then
        return true
    end

    if type_v1 == "string" then
        return false
    end

    if type_v2 == "string" then
        return true
    end

    return false
end

-- 列表排序(多种元素, sort排序只对单一字符串或数值排序, 该排序数值在前字符串在后, 其它类型按原顺序(或自定义排序算法)排至最后)
---@param list table 待排序列表
---@param comp function 自定义冒泡排序函数(默认升序), 接收两个元素, 返回布尔值, true交换两个位置, false保持不变
---@param o_fn function 其它类型元素自定义排序函数(如对象类型), 返回布尔值, true交换两个位置, false保持不变
function table.mixed_sort(list, comp, o_fn)
    assert(type(list) == "table", "排序列表类型不正确")

    comp = function(v1, v2) return mixed_comp(v1, v2, comp, o_fn) end
    table.sort(list, comp)
end
